#include "../include/socket.h"

namespace net {

bool Socket::create() 
{
    // 创建TCP套接字(IPv4)
    // AF_INET: IPv4地址族
    // SOCK_STREAM: 面向连接的TCP协议
    // IPPROTO_TCP: 显式指定TCP协议
    _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (_sockfd < 0) 
    {
        LOG_ERROR("CREATE SOCKET FAILED!");
        return false;
    }
    return true;
}

bool Socket::bind(const std::string &ip, uint16_t port) 
{
    if (_sockfd == -1) return false;

    // 填充sockaddr_in结构
    sockaddr_in addr{};             // 使用{}初始化确保所有字段为0
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);    // 主机字节序转网络字节序(大端)
    
    // 处理IP地址
    if (ip == "0.0.0.0") 
    {
        // 监听所有可用的网络接口
        addr.sin_addr.s_addr = INADDR_ANY;
    } 
    else 
    {
        // 将点分十进制IP转换为二进制形式
        inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
    }
    
    // 绑定地址到套接字
    if (::bind(_sockfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) 
    {
        LOG_FATAL("Bind sockfd:%d failed!", _sockfd);
        return false;
    }
    return true;
}

bool Socket::listen(int backlog) 
{
    if (_sockfd == -1) return false;

    // 将套接字设置为监听模式
    // backlog参数指定等待连接队列的最大长度
    // SOMAXCONN是系统建议的最大值
    if (::listen(_sockfd, backlog) < 0) 
    {
        LOG_FATAL("Sockfd:%d listen failed!", _sockfd);
        return false;
    }
    return true;
}

bool Socket::connect(const std::string &ip, uint16_t port) 
{
    if (_sockfd == -1) return false;

    // 填充目标服务器地址
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    
    // 将点分十进制IP转换为二进制形式
    inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
    
    // 连接到目标服务器
    if (::connect(_sockfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) 
    {
        LOG_ERROR("Connect server failed!");
        return false;
    }
    return true;
}

int Socket::accept() 
{
    if (_sockfd == -1) return -1;

    // 接受一个新连接
    // 返回新的套接字文件描述符，用于与客户端通信
    // 原套接字继续用于监听新连接
    sockaddr_in addr{};
    socklen_t len = sizeof(addr);
    int newfd = ::accept(_sockfd, reinterpret_cast<sockaddr*>(&addr), &len);
    if (newfd < 0) 
    {
        LOG_ERROR("Sockfd:%d accept failed!", _sockfd);
        return -1;
    }
    return newfd;
}

ssize_t Socket::recv(void *buf, size_t len, int flags) {
    if (_sockfd == -1) return -1;

    // 接收数据
    // 返回实际接收的字节数
    // 返回0表示连接关闭
    // 返回-1表示发生错误
    ssize_t ret = ::recv(_sockfd, buf, len, flags);
    if (ret <= 0) 
    {
        // 处理非阻塞模式下的正常情况
        if (errno == EAGAIN || errno == EWOULDBLOCK) 
        {
            // 非阻塞模式下没有数据可读
            return 0;
        }
        
        if (errno == EINTR) 
        {
            // 系统调用被信号中断，可重试
            return 0;
        }
        
        // 其他错误情况
        LOG_ERROR("Sockfd:%d recv failed!", _sockfd);
        return -1;
    }
    return ret;
}

ssize_t Socket::nonBlockRecv(void *buf, size_t len) 
{
    // 调用recv并指定MSG_DONTWAIT标志实现非阻塞接收
    return recv(buf, len, MSG_DONTWAIT);
}

ssize_t Socket::send(const void *buf, size_t len, int flags) 
{
    if (_sockfd == -1) return -1;

    // 发送数据
    // 返回实际发送的字节数
    // 返回-1表示发生错误
    ssize_t ret = ::send(_sockfd, buf, len, flags);
    if (ret < 0) 
    {
        if (errno == EAGAIN || errno == EINTR) 
        {
            return 0;
        }

        LOG_ERROR("Socket send failed!");
        return -1;
    }
    return ret;
}

ssize_t Socket::nonBlockSend(void *buf, size_t len) 
{
    if(len == 0) return 0;
    // 调用send并指定MSG_DONTWAIT标志实现非阻塞发送
    return send(buf, len, MSG_DONTWAIT);
}

void Socket::close() 
{
    // 安全关闭套接字
    if (_sockfd != -1) 
    {
        ::close(_sockfd);
        _sockfd = -1;  // 重置为无效值，避免重复关闭
    }
}

bool Socket::createServer(uint16_t port, const std::string &ip, bool nonBlock) 
{
    // 一站式创建服务器套接字
    if (!create()) return false;
    if (nonBlock) setNonBlock(true);
    if (!bind(ip, port)) return false;
    if (!listen()) return false;
    reuseAddress();     // 设置地址重用，允许快速重启服务器
    // setKeepAlive();     // 设置长连接检测
    // setTcpNoDelay();    // 禁用Nagle算法。
    return true;
}

bool Socket::createClient(uint16_t port, const std::string &ip) 
{
    // 一站式创建客户端套接字
    if (!create()) return false;
    if (!connect(ip, port)) return false;
    return true;
}

void Socket::reuseAddress() 
{
    if (_sockfd == -1) return;

    // 设置SO_REUSEADDR选项，允许在同一地址和端口上重启服务器
    // 避免TIME_WAIT状态导致的"Address already in use"错误
    int val = 1;
    ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    
    // 设置SO_REUSEPORT选项，允许多个进程绑定到同一地址和端口
    // 需要内核支持( Linux 3.9+ )
    ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
}

void Socket::setKeepAlive()
{
    if (_sockfd == -1) return;
    // SO_KEEPALIVE 启用在已连接的套接字上定期传输消息。
    // 如果另一端没有响应，则认为连接已断开并关闭。
    // 这对于检测网络中失效的对等方非常有用。
    int val = 1;
    ::setsockopt(_sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
}

void Socket::setTcpNoDelay()
{
    if (_sockfd == -1) return;
    // TCP_NODELAY 用于禁用 Nagle 算法。
    // Nagle 算法用于减少网络上传输的小数据包数量。
    // 将 TCP_NODELAY 设置为 1 可以禁用该算法，允许小数据包立即发送。
    int val = 1;
    ::setsockopt(_sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
}

void Socket::setNonBlock(bool nonBlock) 
{
    if (_sockfd == -1) return;

    // 获取当前文件状态标志
    int flags = fcntl(_sockfd, F_GETFL, 0);
    if (flags == -1) return;
    
    if (nonBlock) 
    {
        // 添加O_NONBLOCK标志，设置为非阻塞模式
        fcntl(_sockfd, F_SETFL, flags | O_NONBLOCK);
    } 
    else 
    {
        // 清除O_NONBLOCK标志，设置为阻塞模式
        fcntl(_sockfd, F_SETFL, flags & ~O_NONBLOCK);
    }
}

} // namespace net